<?php
/**
 * Created by 惠达浪
 * Email: crazys@126.com
 * Date: 2018/11/22
 * Time: 23:34
 */

namespace app\api\logic;

use app\api\facade\TokenService;
use app\api\model\Attendance;
use app\api\model\ResultProductReport;
use app\api\model\User as UserModel;
use app\api\model\Workcenter;
use app\lib\enum\ErrorCodeEnum;
use app\lib\enum\LoginEnum;
use app\lib\enum\MesEnum;
use app\lib\exception\BaseException;
use app\lib\exception\TokenException;
use think\Exception;
use think\facade\Cache;
use think\facade\Config;
use think\Request;

/**
 * 用户业务逻辑类
 *
 * @package app\api\logic
 */
class User {
    /**
     * 根据token获取用户详细信息
     *
     * @param string $token 令牌
     *
     * @return bool|mixed
     * @throws \think\Exception\DbException
     * @throws TokenException
     */
    public function getUserInfoByToken($token) {
        //验证令牌是否合法
        if (TokenService::verifyToken($token)) {
            //令牌合法时，一定有uid
            $uid = TokenService::getUserIdByToken($token);
            $user = UserModel::get($uid);
            return $user->hidden(['usr_pwd']);
        }

        throw new TokenException();
    }

    /**
     * 设备登录
     *
     * @param string $username  用户名
     * @param string $password  密码
     * @param string $device_no 工作中心设备号
     *
     * @return array 成功时返回user信息与token字符串，失败返回错误原因
     * @throws Exception\DbException
     */
    public function login($username, $password, $device_no) {
        $wc_id = Workcenter::where('device_no', '=', $device_no)->value('id');

        //验证密码
        $user = $this->workStart($username, $password, $wc_id);
        if ($user instanceof UserModel) {
            //一切顺利
            $userModel = $user;
        } else if (isset($user['user'])) {
            //重复登录
            $userModel = $user['user'];
        } else {
            //登录失败
            return $user;
        }
        //无论是否已经上班，只要登录就生成令牌
        $claims = [
            'wid' => $wc_id,
            'uid' => $userModel['id']
        ];

        return $this->makeLoginData($userModel, $claims);
    }

    /**
     * 手机用户登录
     *
     * @param string $username 用户名
     * @param string $password 密码
     *
     * @return array|bool
     * @throws Exception\DbException
     */
    public function mobileLogin($username, $password) {
        $user = $this->checkPassword($username, $password);
        if ($user instanceof UserModel) {
            $claims = ['uid' => $user['id']];
            return $this->makeLoginData($user, $claims);
        }
        return false;
    }

    /**
     * 校验用户密码
     *
     * @param string $username 用户名
     * @param string $password 密码
     *
     * @return UserModel|bool 成功返回用户模型，失败返回false
     * @throws \think\Exception\DbException
     */
    private function checkPassword($username, $password) {
        $user = UserModel::get(['usr_mobile' => $username]);
        if ($user) {
            $salt = Config::get('global.token.salt');
            $encrypt_pwd = md5(sha1($password) . $salt);
            if ($encrypt_pwd === $user['usr_pwd']) {
                return $user->hidden(['usr_pwd']);
            }
        }
        return false;
    }

    /**
     * 生成登录返回数据
     *
     * @param UserModel $user
     * @param array     $claims
     *
     * @return array
     */
    private function makeLoginData(UserModel $user, array $claims) {
        $token = TokenService::generateToken($claims);
        $user->isUpdate(true)->save(['usr_lastlogin' => time()]);
        $result = [
            'user' => $user->toArray(),
            'token' => (string)$token
        ];
        return $result;
    }

    /**
     * 上班打卡
     *
     * @param string $username      用户名
     * @param string $password      密码
     * @param int    $workcenter_id 工作中心编号
     *
     * @return UserModel|array
     * @throws \think\Exception\DbException
     */
    public function workStart($username, $password, $workcenter_id) {
        $user = $this->checkPassword($username, $password);
        if ($user) {
            //检查是否已经登录
            $uid = Cache::get('attendance.user_' . $user['id']);
            if ($uid) {
                return [
                    'msg' => '用户已经上班',
                    'errCode' => ErrorCodeEnum::WORK_ALREADY_START,
                    'user' => $user
                ];
            }

            //创建上班记录
            $setAttendance = $this->setAttendance($user['id'], $workcenter_id, MesEnum::ATTENDANCE_ON);
            if ($setAttendance) {
                //上班成功，写缓存，有效期24小时
                Cache::set('attendance.user_' . $user['id'], $user->toArray(), 3600 * 12);
                return $user;
            }
        }
        return [
            'msg' => '登录失败',
            'errCode' => ErrorCodeEnum::LOGIN_FALLED
        ];
    }

    /**
     * 下班打卡
     *
     * @param string $username      用户名
     * @param string $password      密码
     * @param int    $workcenter_id 工作中心编号
     *
     * @return UserModel|array
     * @throws \think\Exception\DbException
     */
    public function workEnd($username, $password, $workcenter_id) {
        $user = $this->checkPassword($username, $password);
        if ($user) {
            $record = Attendance::whereBetweenTime('attendance_time', time() - 3600, time())->find();
            if ($record) {
                return [
                    'msg' => '用户已经下班',
                    'errCode' => ErrorCodeEnum::WORK_ALREADY_END
                ];
            }
            $setAttendance = $this->setAttendance($user['id'], $workcenter_id, MesEnum::ATTENDANCE_OFF);
            if ($setAttendance) {
                //删除缓存
                Cache::rm('attendance.user_' . $user['id']);
                return $user;
            }
        }
        return [
            'msg' => '登录失败',
            'errCode' => ErrorCodeEnum::LOGIN_FALLED
        ];
    }

    /**
     * 设置出勤状态
     *
     * @param int $uid           用户id
     * @param int $workcenter_id 工作中心编号
     * @param int $attStatus     状态
     *
     * @return UserModel|bool
     */
    private function setAttendance($uid, $workcenter_id, $attStatus) {
        //生成上下班记录
        $data = [
            'workcenter_id' => $workcenter_id,
            'user_id' => $uid,
            'attendance_time' => time(),
            'attendance_status' => $attStatus
        ];

        $attModel = Attendance::create($data);
        return !empty($attModel['id']);
    }

}